/*
 * Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.huawei.cloudphone.virtualdevice.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;

import com.huawei.cloudphone.virtualdevice.common.IVirtualDeviceDataListener;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class VirtualSensor implements SensorEventListener {
    private static final String TAG = "VirtualSensor";
    private SensorManager mSensorManager;
    private IVirtualDeviceDataListener mListener = null;
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private Sensor mSensor;
    private Sensor mAccelerationSensor;

    private boolean mIsStart = false;
    private Map<Integer, Sensor> mSensorMap = new HashMap<>();
    private Map<Integer, Boolean> mSensorActiveMap = new HashMap<>();

    private Map<Integer, String> mSensorTypeToNameMap = new HashMap<Integer, String>(){{

        put(Sensor.TYPE_PROXIMITY, "接近传感器");
        put(Sensor.TYPE_GRAVITY, "重力传感器");
        put(Sensor.TYPE_LINEAR_ACCELERATION, "线性加速度传感器");
        put(Sensor.TYPE_ROTATION_VECTOR, "旋转矢量传感器");
        put(Sensor.TYPE_RELATIVE_HUMIDITY, "湿度传感器");
        put(Sensor.TYPE_AMBIENT_TEMPERATURE, "温度传感器");
        put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, "未校准磁力传感器");
        put(Sensor.TYPE_GAME_ROTATION_VECTOR, "游戏矢量传感器");
        put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, "未校准陀螺仪");
        put(Sensor.TYPE_SIGNIFICANT_MOTION, "大幅动作传感器");
        put(Sensor.TYPE_STEP_DETECTOR, "步数检测器");
        put(Sensor.TYPE_STEP_COUNTER, "计步器");
        put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, "地磁旋转矢量传感器");
        put(Sensor.TYPE_HEART_RATE, "心率传感器");
        put(Sensor.TYPE_POSE_6DOF, "6向姿势传感器");
        put(Sensor.TYPE_STATIONARY_DETECT, "静止检测传感器");
        put(Sensor.TYPE_MOTION_DETECT, "运动检测传感器");
        put(Sensor.TYPE_HEART_BEAT, "心跳传感器");
        put(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT, "低延迟离开身体检测");
        put(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED, "未校准加速度传感器");
        put(Sensor.TYPE_ACCELEROMETER, "加速度传感器");
        put(Sensor.TYPE_MAGNETIC_FIELD, "磁力传感器");
        put(Sensor.TYPE_ORIENTATION, "方向传感器");
        put(Sensor.TYPE_GYROSCOPE, "陀螺仪");
        put(Sensor.TYPE_LIGHT, "光线传感器");
        put(Sensor.TYPE_PRESSURE, "压力传感器");
        put(Sensor.TYPE_TEMPERATURE, "温度传感器2");
        put(22, "倾斜检测传感器");
        put(23, "手势唤醒传感器");
        put(24, "快览手势传感器");
        put(25, "唤醒手势传感器");
        put(26, "抬腕倾斜传感器");
        put(27, "设备方向传感器");
    }};

    public VirtualSensor(SensorManager sensorManager) {
        mSensorManager = sensorManager;
        mAccelerationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        for (Sensor sensor: sensorList) {
            int type = sensor.getType();
            if (type >= Sensor.TYPE_DEVICE_PRIVATE_BASE) {
                continue;
            }
            mSensorActiveMap.put(type, false);
        }
    }

    void registerSensorDataListener(IVirtualDeviceDataListener listener) {
        mListener = listener;
    }

    public void start() {
        Log.i(TAG, "start");
        if (mIsStart) {
            return;
        }
        mHandlerThread = new HandlerThread("sensorThread");
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
        mIsStart = true;
    }

    public void stop() {
        Log.i(TAG, "stop");
        if (!mIsStart) {
            return;
        }
        mHandlerThread.getLooper().quit();
        mIsStart = false;
    }

    public void startProcess(short sensorId) {
        Log.i(TAG, "register sensor id " + sensorId);

        if (mSensorActiveMap.containsKey((int) sensorId)) {
            mSensorActiveMap.replace((int) sensorId, true);
        }
        if (sensorId == 1) {
            mSensorManager.registerListener(this, mAccelerationSensor, SensorManager.SENSOR_DELAY_GAME, mHandler);
            return;
        }
        mSensor = mSensorManager.getDefaultSensor(sensorId);
        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME, mHandler);
    }

    public void stopProcess(short sensorId) {
        Log.i(TAG, "unregister sensor id " + sensorId);

        if (mSensorActiveMap.containsKey((int) sensorId)) {
            mSensorActiveMap.replace((int) sensorId, false);
        }

        if (sensorId == 1) {
            mSensorManager.unregisterListener(this, mAccelerationSensor);
        }
        mSensor = mSensorManager.getDefaultSensor(sensorId);
        mSensorManager.unregisterListener(this, mSensor);
    }

    public String getSensorStatus() {
        StringBuilder status = new StringBuilder();

        for (Map.Entry<Integer, Boolean> entry : mSensorActiveMap.entrySet()) {
            status.append("\n");
            status.append(getSensorNameByType(entry.getKey()));
            status.append(" : ");
            if (entry.getValue()) {
                status.append("启用");
            } else {
                status.append("关闭");
            }
        }
        return status.toString();
    }

    private String getSensorNameByType(Integer type) {
        return mSensorTypeToNameMap.getOrDefault(type, type.toString());
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        if (mListener == null) {
            return;
        }
        mListener.onRecvData(sensorEvent);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }
}
